﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using System.Windows.Controls.Ribbon;
using SHomeWorkshop.LunarConcept.Controls;
using System.Xml;
using SHomeWorkshop.LunarConcept.Tools;
using SHomeWorkshop.LunarConcept.ModifingManager;
using System.Windows;
using SHomeWorkshop.LunarConcept.Widgets.Interfaces;

namespace SHomeWorkshop.LunarConcept.Commands
{
    /// <summary>
    /// 创建时间：2012年1月18日
    /// 创建者：  杨震宇
    /// 
    /// 主要用途：将当前选定的部件组合起来。
    /// </summary>
    public static class GroupWidgetCommand
    {
        #region 构造方法=====================================================================================================

        /// <summary>
        /// [静态][构造方法]
        /// 
        /// ——此方法会初始化并向WPF系统注册一个RoutedUICommand。
        /// </summary>
        static GroupWidgetCommand()//类型构造器
        {
            routedUICmd = new RoutedUICommand(
                "GroupWidgetCommand",
                "GroupWidgetCommand",
                typeof(GroupWidgetCommand),//创建RoutedUICommand对象
                null);//本程序考虑支持“命令模式”因此，这些命令完全没有必要直接支持快捷键。

            routedUICmd.InputGestures.Add(new KeyGesture(Key.G, ModifierKeys.Control, "Ctrl + G"));

            cmdBinding.Command = routedUICmd;
            cmdBinding.CanExecute += new CanExecuteRoutedEventHandler(cmdBinding_CanExecute);
            cmdBinding.Executed += new ExecutedRoutedEventHandler(cmdBinding_Executed);
        }

        #endregion

        #region 字段与属性===================================================================================================

        private static CommandBinding cmdBinding = new CommandBinding();
        /// <summary>
        /// 用在主窗口CommandBindings集合中的命令绑定。
        /// 
        /// 它的Command是RoutedUICommand。
        /// ——因此，RoutedUICommand是否可以运行将由CmdBinding的CanExecute事件决定。
        /// ——而且，RoutedUICommand的执行也是通过CmdBinding的Execute事件来进行的。
        /// </summary>
        public static CommandBinding CmdBinding
        {
            get { return cmdBinding; }
        }

        private static RoutedUICommand routedUICmd;
        /// <summary>
        /// [只读静态属性]表示在WPF系统中注册的一个RoutedUICommand。
        /// ——必须和CommandBinding配合才能使用。
        ///     CommandBinding要添加到主窗口的CommandBindings集合中；
        ///     RoutedUICommand则要向WPF系统注册。
        ///     
        /// ★说明：使用静态属性是因为这样在Xaml代码中比较便于绑定。
        /// </summary>
        public static RoutedUICommand RoutedUICmd
        {
            get { return routedUICmd; }
        }

        #endregion

        #region 方法=========================================================================================================

        /// <summary>
        /// 判断命令是否可以执行。
        /// ——由于可以直接调用Execute()方法，因此，即使被禁用，也不是不能执行相关功能！！！
        /// </summary>
        static void cmdBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            //考虑到性能问题，全部取消此判断。反正执行时会判断。
            //if (Globals.MainWindow == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //EditorManager manager = Globals.MainWindow.EditorManager;
            //if (manager == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //PageEditor mainPe = manager.GetMainSelectedPageEditor();
            //if (mainPe == null)
            //{
            //    e.CanExecute = false; return;
            //}

            //List<Widgets.Widget> selectedWidgetInPageEditor = mainPe.GetSelectedWidgetsList(true);
            //if (selectedWidgetInPageEditor.Count < 2)//同一页中，两个以上部件才有必要组合。
            //{
            //    e.CanExecute = false; return;
            //}

            e.CanExecute = true;
            return;
        }

        /// <summary>
        /// 命令被触发时，会调用本事件处理器方法。
        /// ——本方法实际上是调用ExeCute()这个静态方法来实现特定功能。
        /// </summary>
        static void cmdBinding_Executed(object sender, ExecutedRoutedEventArgs e)
        {
            LunarMessage.Warning(Execute());
        }

        /// <summary>
        /// [公开静态方法]即使此命令处于禁用状态，也可以通过代码调用此方法来执行特定任务！！！
        /// 
        /// 当被绑定的命令被调用（触发）时，会引发cmdBinding_Executed事件。
        /// 在cmdBinding_Executed事件处理器方法中已添加了调用Execute()方法的代码。
        /// 
        /// ——因此，触发命令，就相当于调用此方法！！！
        /// </summary>
        public static string Execute()
        {
            if (Globals.MainWindow == null) return "　　未找到Globals.MainWindow。";

            EditorManager manager = Globals.MainWindow.EditorManager;
            if (manager == null) return "　　未找到页面管理器。";

            PageEditor mainPe = manager.GetMainSelectedPageEditor();
            if (mainPe == null) return "　　未找到活动页面。";

            List<Widgets.Widget> selectedWidgetsList = mainPe.GetSelectedWidgetsList(true);
            if (selectedWidgetsList.Count < 2)
            {
                return "　　组合功能用以将同一页中两个或更多的部件封装在一起，一个及以下部件没有必要封装。";
            }

            //如果选定一条与其它选定的部件毫不相干的连接线，则提示，则不会被组合！！！
            for (int i1 = selectedWidgetsList.Count - 1; i1 >= 0; i1--)
            {
                Widgets.StraitLineWidget sw = selectedWidgetsList[i1] as Widgets.StraitLineWidget;
                if (sw == null) continue;

                bool startLinked = false; bool endLinked = false;
                for (int i2 = selectedWidgetsList.Count - 1; i2 >= 0; i2--)
                {
                    if (sw.StartMasterId == selectedWidgetsList[i2].Id) { startLinked = true; }

                    if (sw.EndMasterId == selectedWidgetsList[i2].Id) { endLinked = true; }
                }

                if ((startLinked == false || endLinked == false) && sw.IsLinked)
                {
                    selectedWidgetsList.Remove(sw);
                    //选定的某个连接线至少有一个点与选定的所有ContentWidget都不相干。
                }
            }

            List<ILinkableLine> allLinkedLines = new List<ILinkableLine>();
            List<ILinkableLine> startLinkedLines = new List<ILinkableLine>();
            List<ILinkableLine> endLinkedLines = new List<ILinkableLine>();

            mainPe.GetLinkdeLines(selectedWidgetsList, ref allLinkedLines, ref startLinkedLines, ref endLinkedLines);

            foreach (Widgets.Interfaces.ILinkableLine linkedLine in allLinkedLines)
            {
                Widgets.Widget w = linkedLine as Widgets.Widget;
                if (w == null) continue;

                if (selectedWidgetsList.Contains(w) == false)
                    selectedWidgetsList.Add(w);
            }

            //foreach (Widgets.Widget w in selectedWidgetsList)
            //{
            //    Widgets.RectangleWidget rw = w as Widgets.RectangleWidget;
            //    if (rw == null) continue;

            //    if (rw.IsPresentationArea) return "选定的部件中含有被标记为“演示区域”的矩形部件，不允许组合！";
            //}

            var presentationAreasCount = 0;
            for (int i = selectedWidgetsList.Count - 1; i >= 0; i--)
            {
                Widgets.RectangleWidget rw = selectedWidgetsList[i] as Widgets.RectangleWidget;
                if (rw != null && rw.IsPresentationArea)
                {
                    selectedWidgetsList.RemoveAt(i);
                    rw.IsSelected = false;
                    presentationAreasCount++;
                }
            }

            ModifingInfo info = new ModifingInfo() { ModifingDescription = "部件组合" };
            manager.GetSelectedPageEditorStatus(info);
            manager.GetSelectedWidgetStatus_Old(info);

            ModifingItem<Action, ModifingInfo> mi = new ModifingItem<Action, ModifingInfo>(info);
            Widgets.GroupWidget gw = new Widgets.GroupWidget(mainPe);

            XmlNode pageWidgetSetNode = mainPe.XmlData.SelectSingleNode(XmlTags.WidgetSetTag);
            if (pageWidgetSetNode == null)
            {
                return "　　未找到此页的“WidgetSet”节点，无法继续组合。";
            }

            gw.XmlData = pageWidgetSetNode.AppendXmlAsChild(Properties.Resources.GroupXml);
            gw.NewID();

            if (gw.XmlData == null)
            {
                return "　　未能在当前页的“WidgetSet”节点中插入初始“组”节点，无法继续组合。";
            }

            XmlNode groupWidgetSetNode = gw.XmlData.SelectSingleNode(XmlTags.WidgetSetTag);
            if (groupWidgetSetNode == null)
            {
                groupWidgetSetNode = gw.XmlData.AppendXmlAsChild("<" + XmlTags.WidgetSetTag + " />");
                if (groupWidgetSetNode == null)
                {
                    return "　　未能找到新插入的“组”节点的“WidgetSet”子节点，且未能自动添加，无法继续组合。";
                }
            }

            #region 先求出相关区域的尺寸。

            double minLeft = double.MaxValue, minTop = double.MaxValue;
            double maxRight = 0, maxBottom = 0;

            bool hasLineWidgets = false;

            foreach (Widgets.Widget w in selectedWidgetsList)
            {
                if (w is Widgets.LineWidget) hasLineWidgets = true;

                //组合时考虑线宽，结果会极为恐怖（因为情况太复杂）。根本无法达到想要的效果。
                //Widgets.LineWidget lw = w as Widgets.LineWidget;
                //if (lw != null)
                //{
                //    Point topLeft = lw.TopLeft;
                //    Point bottomRight = lw.BottomRight;

                //    double halfWidth = lw.LineWidth / 2;

                //    topLeft = new Point(topLeft.X - halfWidth, topLeft.Y - halfWidth);
                //    bottomRight = new Point(bottomRight.X + lw.LineWidth, bottomRight.Y + lw.LineWidth);//还要考虑左和上已经占去的半个线宽。

                //    if (topLeft.X < minLeft) minLeft = topLeft.X;
                //    if (topLeft.Y < minTop) minTop = topLeft.Y;
                //    if (bottomRight.X > maxRight) maxRight = bottomRight.X;
                //    if (bottomRight.Y > maxBottom) maxBottom = bottomRight.Y;
                //}
                //else
                //{
                if (w.TopLeft.X < minLeft) minLeft = w.TopLeft.X;

                if (w.TopLeft.Y < minTop) minTop = w.TopLeft.Y;

                double right = w.TopLeft.X + w.BottomRight.X;
                if (right > maxRight) maxRight = right;

                double bottom = w.TopLeft.Y + w.BottomRight.Y;
                if (bottom > maxBottom) maxBottom = bottom;
                //}
            }

            #endregion

            Point baseTopLeft = new Point(minLeft, minTop);

            //删除外部所有选定组件。
            foreach (Widgets.Widget w in selectedWidgetsList)
            {
                Widgets.ContentWidget cw = w as Widgets.ContentWidget;
                if (cw != null)
                {
                    Point newLocation = new Point(cw.Location.X - minLeft, cw.Location.Y - minTop);
                    Action actLocation = new Action(mainPe.Id, w.Id, w.GetType().Name, XmlTags.LocationTag,
                        cw.Location.ToString(), newLocation.ToString());
                    cw.Location = newLocation;
                    mi.AddAction(actLocation);
                }

                if (w.XmlData != null)
                {
                    Action actDelWidget = new Action(ActionType.WidgetDeleted, mainPe.Id, w.Id,
                        w.XmlData.OuterXml, null);

                    XmlNode parentNode = w.XmlData.ParentNode;
                    if (parentNode != null)
                    {
                        parentNode.RemoveChild(w.XmlData);
                    }

                    mainPe.RemoveWidget(w);
                    mi.AddAction(actDelWidget);

                    //从文档中删除后，移动到“组”内部。
                    gw.MainCanvas.Children.Add(w);

                    Widgets.LineWidget lw = w as Widgets.LineWidget;
                    if (lw != null)
                    {
                        lw.RefreshPointWhenGroupIn(baseTopLeft);
                    }

                    w.IsSelected = false;
                    groupWidgetSetNode.AppendChild(w.XmlData);
                }
            }

            //删除挂接的所有连接关系线。
            foreach (Widgets.Interfaces.ILinkableLine linkedLine in startLinkedLines)
            {
                Widgets.ArrowLineWidget swStart = linkedLine as Widgets.ArrowLineWidget;
                if (swStart == null) continue;

                Action actDel = new Action(ActionType.WidgetDeleted, mainPe.Id, swStart.Id, swStart.XmlData.OuterXml, null);
                mainPe.RemoveWidget(swStart);
                mi.AddAction(actDel);
            }

            foreach (Widgets.Interfaces.ILinkableLine linkedLine in endLinkedLines)
            {
                Widgets.ArrowLineWidget swEnd = linkedLine as Widgets.ArrowLineWidget;
                if (swEnd == null) continue;

                Action actDel = new Action(ActionType.WidgetDeleted, mainPe.Id, swEnd.Id, swEnd.XmlData.OuterXml, null);
                mainPe.RemoveWidget(swEnd);
                mi.AddAction(actDel);
            }

            //按默认值设置属性
            //gw.WidgetForeColor = manager.GroupStyle.WidgetForeColor;
            //gw.WidgetBackColor = manager.GroupStyle.WidgetBackColor;
            //gw.WidgetLineWidth = manager.GroupStyle.WidgetLineWidth;
            //gw.WidgetLineColor = manager.GroupStyle.WidgetLineColor;
            //gw.WidgetPadding = manager.GroupStyle.WidgetPadding;
            //已改用样式。

            if (hasLineWidgets)
            {
                gw.Location = new Point(minLeft - manager.GroupStyle.WidgetPadding.Left -
                                            manager.GroupStyle.WidgetLineWidth - 10,//内间距
                                        minTop - manager.GroupStyle.WidgetPadding.Top -
                                            manager.GroupStyle.WidgetLineWidth - 10//内间距
                    );//注意必须先设点坐标，再加Action。
                gw.WidgetPadding = new Thickness(10);
            }
            else
            {
                gw.Location = new Point(minLeft - manager.GroupStyle.WidgetPadding.Left -
                                            manager.GroupStyle.WidgetLineWidth,
                                        minTop - manager.GroupStyle.WidgetPadding.Top -
                                            manager.GroupStyle.WidgetLineWidth
                    );//注意必须先设点坐标，再加Action。
            }

            gw.IsShadowVisible = manager.GroupStyle.IsShadowVisible;

            Action actInsertGroupWidget = new Action(ActionType.WidgetAdded, mainPe.Id, gw.Id,
                 null, gw.XmlData.OuterXml);

            mainPe.AddWidget(gw);
            gw.Build();

            mi.AddAction(actInsertGroupWidget);

            gw.IsMainSelected = true;
            manager.GetSelectedWidgetStatus_New(info);

            if (mainPe.MasterManager != null)
            {
                mainPe.MasterManager.RegisterModifingItem(mi);
                mainPe.MasterManager.RefreshAutoNumberStrings();
            }

            if (presentationAreasCount > 0)
            {
                MessageBox.Show("　　选定的部件中含有被标记为“演示区域”的矩形部件，演示区域不允许组合，已忽略！",
                    Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Information);
            }

            return string.Empty;
        }

        #endregion
    }
}
